package customExecutor;

import com.alibaba.ttl.TransmittableThreadLocal;
import com.alibaba.ttl.threadpool.TtlExecutors;
import org.junit.Test;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Package: com.h2cloud.ThreadLocalTest.customExecutor
 * @ClassName: Main
 * @Author: h2cloud
 * @CreateTime: 2023/12/21 11:09 下午
 * @Description:
 */
public class Main {
    @Test
    public void ITLTest() throws Exception {
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        System.out.println("main thread fisrt set ThreadLocal");
        ITLCurrentUser.UserInfo userInfo = new ITLCurrentUser.UserInfo();
        userInfo.setName("userInfo：h2cloud");
        ITLCurrentUser.set(userInfo);
        executorService.submit(() -> fun1());
        executorService.submit(() -> fun1());

        Thread.sleep(2000);
        System.out.println("main thread reset ThreadLocal");
        ITLCurrentUser.UserInfo userInfo2 = new ITLCurrentUser.UserInfo();
        userInfo2.setName("userInfo2：h2cloud");
        ITLCurrentUser.set(userInfo2);
        executorService.submit(() -> fun1());
        executorService.submit(() -> fun1());
    }

    public void fun1() {
        System.out.println(Thread.currentThread().getName() + ": fun1 = " + ITLCurrentUser.get());
    }


    @Test
    public void TTLTest() throws Exception {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        executorService = TtlExecutors.getTtlExecutorService(executorService);

        System.out.println("main thread fisrt set ThreadLocal");
        TTLCurrentUser.UserInfo userInfo = new TTLCurrentUser.UserInfo();
        userInfo.setName("userInfo：h2cloud");
        TTLCurrentUser.set(userInfo);

        executorService.submit(() -> fun2());
        executorService.submit(() -> fun2());

        Thread.sleep(2000);
        System.out.println("main thread reset ThreadLocal");
        TTLCurrentUser.UserInfo userInfo2 = new TTLCurrentUser.UserInfo();
        userInfo2.setName("userInfo2：h2cloud");
        TTLCurrentUser.set(userInfo2);
        executorService.submit(() -> fun2());
        executorService.submit(() -> fun2());
    }

    public void fun2() {
        System.out.println(Thread.currentThread().getName() + ": fun11 = " + TTLCurrentUser.get());
    }


    @Test
    public void TestCustomExecutor() throws Exception {
        System.out.println("main thread fisrt set ThreadLocal");
        ITLCurrentUser.UserInfo userInfo = new ITLCurrentUser.UserInfo();
        userInfo.setName("h2cloud");
        ITLCurrentUser.set(userInfo);

        AtomicInteger threadNumber = new AtomicInteger(0);
        ExecutorService asyncExecutorService = new TransmittableThreadPoolExecutor(
                2,
                2,
                60,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(16),
                new ThreadFactory() {
                    @Override
                    public Thread newThread(Runnable r) {
                        return new Thread(r, "async-exec-" + threadNumber.getAndIncrement());
                    }
                },
                new RejectedExecutionHandler() {
                    @Override
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                        if (!executor.isShutdown()) {
                            try {
                                //尝试阻塞式加入任务队列
                                executor.getQueue().put(r);
                            } catch (InterruptedException e) {
                                //保持线程的中端状态
                                Thread.currentThread().interrupt();
                            }
                        }
                    }
                });

        asyncExecutorService.submit(() -> doSomething());
        asyncExecutorService.submit(() -> doSomething());

        Thread.sleep(2000);
        System.out.println("main thread reset ThreadLocal");
        ITLCurrentUser.UserInfo userInfo2 = new ITLCurrentUser.UserInfo();
        userInfo2.setName("userInfo2：h2cloud");
        ITLCurrentUser.set(userInfo2);

        asyncExecutorService.submit(() -> doSomething());
        asyncExecutorService.submit(() -> doSomething());

        Thread.sleep(5000);
    }

    public void doSomething() {
        System.out.println(Thread.currentThread().getName() + "  " + ITLCurrentUser.get());
    }


    // 线程池复用前提下，将线程变量传递给子线程
    // ThreadLocal
    @Test
    public void TestMoreSubThreadV1() {
        ThreadLocal<String> threadLocal = new ThreadLocal<>();
        ExecutorService ES = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 10; i++) {
            threadLocal.set("hello" + i);
            ES.submit(() -> {
                        System.out.println(Thread.currentThread().getName() + ": " + threadLocal.get());
                        ES.submit(() -> {
                            System.out.println(Thread.currentThread().getName() + ": " + threadLocal.get());
                        });
                    }
            );
        }
    }

    // 线程池复用前提下，将线程变量传递给子线程
    // InheritableThreadLocal
    @Test
    public void TestMoreSubThreadV2() {
        InheritableThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
        ExecutorService ES = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 10; i++) {
            threadLocal.set("hello" + i);
            ES.submit(() -> {
                        System.out.println(Thread.currentThread().getName() + ": " + threadLocal.get());
                        ES.submit(() -> {
                            System.out.println(Thread.currentThread().getName() + ": " + threadLocal.get());
                        });
                    }
            );
        }
    }

    // 线程池不复用前提下，将线程变量传递给子线程
    // InheritableThreadLocal
    @Test
    public void TestMoreSubThreadV2_2() {
        InheritableThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
        for (int i = 0; i < 10; i++) {
            threadLocal.set("hello" + i);
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + ": " + threadLocal.get());
                new Thread(() -> {
                    System.out.println(Thread.currentThread().getName() + ": " + threadLocal.get());
                }).start();
            }).start();
        }
    }

    // 线程池复用前提下，将线程变量传递给子线程
    // TransmittableThreadLocal
    @Test
    public void TestMoreSubThreadV3() {
        TransmittableThreadLocal<String> threadLocal = new TransmittableThreadLocal<>();
        ExecutorService ES = TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(3));
        for (int i = 0; i < 10; i++) {
            threadLocal.set("hello" + i);
            ES.submit(() -> {
                        System.out.println(Thread.currentThread().getName() + ": " + threadLocal.get());
                        ES.submit(() -> {
                            System.out.println(Thread.currentThread().getName() + ": " + threadLocal.get());
                        });
                    }
            );
        }
    }

}
